<template>
  <view class="ui-uploader">
    <view class="ui-uploader-wrapper">
      <!-- 上传的图片预览 -->
      <view class="ui-uploader-preview" v-for="(file,index) in fileList" :key="index">
        <!-- 预览的图片 -->
        <view class="preview-image" @click="handleClickImage(file,index)">
          <image class="preview-image--img" :src="file.url" />
        </view>

        <!-- 移除按钮 -->
        <view
          class="preview-icon--delete"
          v-if="deletable && file.status !== 3"
          @click="handleClickDeleteImage(file,index)"
        >
          <uiIcon type="ui-icon" name="ui-icon-cross" size="28"></uiIcon>
        </view>
        <!-- 遮罩层 -->
        <view class="preview-mask" v-if="file.status === 3 || file.status === 'failed' ">
          <view class="preview-mask--container">
            <template v-if="file.status === 3">
              <slot name="mask">
                <uiLoading color="#fff" size="32"></uiLoading>
                <text class="preview-mask--txt ui-txt ui-txt-caption-sm">上传中...</text>
              </slot>
            </template>
            <template v-else>
              <uiIcon type="ui-icon" name="ui-icon-warning-o" color="#fff" size="48"></uiIcon>
              <text class="preview-mask--txt ui-txt ui-txt-caption-sm">{{file.message}}</text>
            </template>
          </view>
        </view>
      </view>
      <!-- 上传 -->
      <view class="uploader-upload" @click="handleClickUpload" v-if="fileList.length < maxCount">
        <!-- 支持用户自定义上传样式 -->
        <slot v-if="$slots.default"></slot>
        <template v-else>
          <view class="upload-icon">
            <uiIcon color="#dcdee0" type="ui-icon" name="ui-icon-photograph" size="48"></uiIcon>
          </view>
          <!-- 上传说明文字 -->
          <view class="upload-text ui-txt ui-txt-caption-sm">{{uploadText}}</view>
        </template>
        <!-- input -->
      </view>
    </view>
  </view>
</template>

<script>
import uiIcon from "@/components/base/icon/index.vue";
import uiLoading from "@/components/base/loading/index.vue";

import { overSize, toArray } from "./utils";

import { isString, isPromise } from "@/utils/validate/data.js";
import { getUUID } from "@/utils/number.js";

/**
 *  文件上传
 *
 *    TODO:
 *
 *      1. 支持文件类型拓展(其他文件类型)
 *      2. 优化自定义上传或者内置上传函数
 *      3. 优化图片的预览
 *      4. 优化异步上传的处理
 *
 *
 */

export default {
  name: "uiUploader",
  components: { uiIcon, uiLoading },
  props: {
    // 文件内容
    value: {
      type: Array,
      default() {
        return [];
      }
    },
    // 是否自动上传
    upload_auto: {
      type: Boolean,
      default: true
    },

    // 是否禁止
    disabled: Boolean,
    // 上传说明文字
    uploadText: String,
    // 多文件上传
    multiable: {
      type: Boolean,
      default: false
    },

    afterRead: Function,
    beforeRead: Function,
    beforeDelete: Function,
    previewSize: [Number, String],

    name: {
      type: [Number, String],
      default: ""
    },
    accept: {
      type: String,
      default: "image/*"
    },
    // 文件最大size
    maxSize: {
      type: [Number, String],
      default: Number.MAX_VALUE
    },
    // 文件最大数量
    maxCount: {
      type: [Number, String],
      default: Number.MAX_VALUE
    },

    // 是否允许移除
    deletable: {
      type: Boolean,
      default: true
    },
    // 是否允许预览图片
    previewImage: {
      type: Boolean,
      default: true
    }
  },
  data() {
    return {
      fileList: []
    };
  },
  computed: {
    // for form
    // fileList() {
    //   return fileList;
    // }
  },
  created() {
    // 处理用户传入的图片数据
    let files = toArray(this.value);
    let fileList = [];
    for (let index = 0; index < files.length; index++) {
      const file = files[index];
      const url = isString(file) ? file : file.url;
      fileList.push({
        url: url,
        status: 1
      });
    }

    this.fileList = fileList;
  },
  mounted() {},
  methods: {
    /**
     * 触发删除文件
     *
     *  - 这个文件是默认的数据 或者已经上传的文件
     *  - 这个文件是待上传或者上传失败的文件内容
     *
     * @param { Object } file 需要删除的图片
     *
     */
    handleClickDeleteImage(file, index) {
      this.fileList.splice(this.fileList.indexOf(file), 1);
      this.$emit("change", this.fileList);
    },

    /**
     * 点击图片触发的事件
     *
     *  - 一般是预览图片
     *  - 是否存在替换图片的需求？
     *
     */
    handleClickImage(file, index) {
      if (this.previewImage) {
        // 先获取当前预览的图片数据
        let files = this.fileList
          .filter(item => item.status == 2 || item.status == 1)
          .map(item => item.url);
        // 使用uni自带的图片预览
        uni.previewImage({
          current: index,
          urls: files,
          loop: true
        });
      }
    },
    /**
     * 点击触发选择图片
     */
    handleClickUpload() {
      if (this.disabled) {
        return;
      }
      // 触发选择图片
      uni.chooseImage({
        count: this.multiable ? 9 : 1,
        success: event => {
          let files = event.tempFiles;
          // 是否定义了上传前校验
          if (this.beforeRead) {
            const response = this.beforeRead(files);
            if (!response) {
              return;
            }
            if (isPromise(response)) {
              response
                .then(() => {
                  this.readFile(files);
                })
                .catch();

              return;
            }
          }
          // 第二步获取图片的信息
          this.readFile(files);
        }
      });
    },

    readFile(files) {
      // 判断当前文件是否超过设置的最大size
      const oversize = overSize(files, this.maxSize);
      Array.isArray(files) || (files = [files]);
      // 判断是否超过最大数量限制
      const maxCount = this.maxCount - this.fileList.length;

      // 如果多选选择的文件超过maxCount 那么就截取
      if (files.length > maxCount) {
        files = files.slice(0, maxCount);
      }

      // 处理图片的信息
      files.forEach(file => {
        // 生成一个唯一ID
        file.id = getUUID("16");
        // 文件的 地址
        file.url = file.path;
        // 状态
        file.status = 2;
        // 大小
        file.size = file.size;
        // 文件名称
        file.name = file.name;
      });
      this.onAfterRead(files, oversize);
    },

    /**
     * 判断文件大小、数量等完成后 进行文件的上传操作
     *
     */
    onAfterRead(files, oversize) {
      if (oversize) {
        this.$emit("oversize", files);
        return;
      }
      // 是否自动上传
      if (this.upload_auto) {
        // 如果是自动上传 那么就直接返回上传后的图片路径地址
        let uploadingFileList = [],
          uploadingPromise = [];
        for (let index = 0; index < files.length; index++) {
          const file = {
            ...files[index],
            // 上传中...
            status: 3,
            index
          };
          // 生成上传文件的对象
          uploadingFileList.push(file);
          // 生成上传文件的 异步对象
          uploadingPromise.push(
            this.upload(file)
              .then(data => {
                file.url = data.url;
                file.status = data.status;
                file.message = data.message;
                return Promise.resolve(data);
              })
              .catch(error => {
                file.url = files[index].url;
                file.status = "failed";
                file.message = "上传失败";
                return Promise.reject(error);
              })
          );
        }
        // 显示上传中...
        this.fileList = this.fileList.concat(uploadingFileList);

        Promise.all(uploadingPromise)
          .then(function(data) {
            console.log("上传完成");
          })
          .catch(function(res) {});
      } else {
        // 需要返回一个文件对象
        // this.$emit("input", [...this.fileList, ...toArray(files)]);
        this.fileList = this.fileList.concat(files);
        this.$emit("change", [...this.fileList, ...toArray(files)]);
      }
    },

    upload(file) {
      return new Promise((resolve, reject) => {
        let params = {};
        setTimeout(_ => {
          resolve({
            ...file,
            url:
              "http://10.159.62.247:80/group1/M00/00/01/Cp8-915u0zCAMTLZAAAzDQ4sHL4054.png",
            status: file.index % 2 === 1 ? 1 : "failed",
            message: "上传失败"
          });
        }, 2000);
      });
    }
  }
};
</script>

<style scoped lang="scss">
</style>
